package com.silence.gmall.product.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.silence.gmall.constant.ProductRedisStringConstant;
import com.silence.gmall.product.assembler.SkuAttrValueFactory;
import com.silence.gmall.product.assembler.SkuImageFactory;
import com.silence.gmall.product.assembler.SkuInfoFactory;
import com.silence.gmall.product.assembler.SkuSaleAttrValueFactory;
import com.silence.gmall.product.domain.entity.SkuAttrValue;
import com.silence.gmall.product.domain.entity.SkuImage;
import com.silence.gmall.product.domain.entity.SkuInfo;
import com.silence.gmall.product.domain.entity.SkuSaleAttrValue;
import com.silence.gmall.product.domain.repository.SkuAttrValueRepository;
import com.silence.gmall.product.domain.repository.SkuImageRepository;
import com.silence.gmall.product.domain.repository.SkuInfoRepository;
import com.silence.gmall.product.domain.repository.SkuSaleAttrValueRepository;
import com.silence.gmall.product.dto.SkuInfoDto;
import com.silence.gmall.product.enums.OnSaleEnum;
import com.silence.gmall.product.record.SkuContext;
import com.silence.gmall.product.service.SkuInfoService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.redisson.api.RBloomFilter;
import org.redisson.api.RedissonClient;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * @Author silence
 * @Description 针对表【sku_info(库存单元表)】的数据库操作Service实现
 * @Date 2025-08-17 16:28:16
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class SkuInfoServiceImpl implements SkuInfoService {

    /**
     * SkuInfoRepository 的注入
     */
    private final SkuInfoRepository skuInfoRepository;

    /**
     * SkuInfoFactory 的注入
     */
    private final SkuInfoFactory skuInfoFactory;

    /**
     * SkuAttrValueRepository 的注入
     */
    private final SkuAttrValueRepository skuAttrValueRepository;

    /**
     * SkuAttrValueFactory 的注入
     */
    private final SkuAttrValueFactory skuAttrValueFactory;

    /**
     * SkuSaleAttrValueRepository 的注入
     */
    private final SkuSaleAttrValueRepository skuSaleAttrValueRepository;

    /**
     * SkuSaleAttrValueFactory 的注入
     */
    private final SkuSaleAttrValueFactory skuSaleAttrValueFactory;

    /**
     * SkuImageRepository 的注入
     */
    private final SkuImageRepository skuImageRepository;

    /**
     * SkuImageFactory 的注入
     */
    private final SkuImageFactory skuImageFactory;

    /**
     * RedisTemplate 的注入
     */
    private final StringRedisTemplate stringRedisTemplate;

    /**
     * RedissonClient 的注入
     */
    private final RedissonClient redissonClient;

    /**
     * 添加sku
     *
     * @param reqVo 请求参数
     */
    @Override
    public void saveSkuInfo(SkuInfoDto reqVo) {
        // 保存SkuInfo
        SkuInfo skuInfo = skuInfoFactory.skuInfoDto2SkuInfo(reqVo);
        skuInfoRepository.save(skuInfo);

        // skuId 获取
        Long skuId = skuInfo.getId();
        // spuId 获取
        Long spuId = skuInfo.getSpuId();

        // 保存库存单元属性值
        if (CollectionUtils.isNotEmpty(reqVo.getSkuAttrValueList())) {
            List<SkuAttrValue> skuAttrValueList = skuAttrValueFactory.skuAttrValueDtoList2SkuAttrValueListWithContext(reqVo.getSkuAttrValueList(), skuId);
            skuAttrValueRepository.saveBatch(skuAttrValueList, skuAttrValueList.size());
        }

        // 保存库存单元销售属性值
        if (CollectionUtils.isNotEmpty(reqVo.getSkuSaleAttrValueList())) {
            List<SkuSaleAttrValue> skuSaleAttrValueList = skuSaleAttrValueFactory
                    .skuSaleAttrValueDtoList2SkuSaleAttrValueListWithContext(reqVo.getSkuSaleAttrValueList(),
                            SkuContext.builder().skuId(skuId).spuId(spuId).build());
            skuSaleAttrValueRepository.saveBatch(skuSaleAttrValueList, skuSaleAttrValueList.size());
        }

        // 保存库存单元图片
        if (CollectionUtils.isNotEmpty(reqVo.getSkuImageList())) {
            List<SkuImage> skuImageList = skuImageFactory.skuImageList2SkuImageDtoListWithContext(reqVo.getSkuImageList(), skuId);
            skuImageRepository.saveBatch(skuImageList, skuImageList.size());
        }

        // 添加 skuId 到布隆过滤器
        RBloomFilter<Long> skuIdBloomFilter = redissonClient.getBloomFilter(ProductRedisStringConstant.PRODUCT_SKU_ID_LIST_KEY);
        skuIdBloomFilter.add(skuId);
    }

    /**
     * 修改sku
     *
     * @param reqVo 请求参数
     */
    @Override
    public void updateSkuInfo(SkuInfoDto reqVo) {
        // 修改SkuInfo
        SkuInfo skuInfo = skuInfoFactory.skuInfoDto2SkuInfo(reqVo);
        skuInfoRepository.updateById(skuInfo);

        // 延迟双删
        stringRedisTemplate.delete(ProductRedisStringConstant.PRODUCT_SKU_INFO_KEY.formatted(skuInfo.getId()));

        // 自己 new Thread 会有 oom 风险，无限请求不停的 new 就会 oom
        // Runnable runnable = () -> {
        //     try {
        //         TimeUnit.SECONDS.sleep(10L);
        //     } catch (InterruptedException _) {
        //         Thread.currentThread().interrupt();
        //     }
        // };
        // runnable.run();

        ScheduledExecutorService pool = Executors.newScheduledThreadPool(4);

        try (pool) {
            pool.schedule(() -> stringRedisTemplate.delete(ProductRedisStringConstant.PRODUCT_SKU_INFO_KEY
                    .formatted(skuInfo.getId())), 10, TimeUnit.SECONDS);
        }

    }

    /**
     * 根据SKU ID查询详情信息
     *
     * @param skuId skuId
     * @return 详情信息
     */
    @Override
    public SkuInfoDto getSkuInfo(Long skuId) {
        SkuInfoDto skuInfoDto = skuInfoRepository.getSkuInfoById(skuId);

        if (skuInfoDto == null) {
            log.warn("SKU ID: {} does not exist in the database", skuId);
            return null;
        }
        return skuInfoDto.setSkuImageList(skuImageFactory.skuImageList2SkuImageDtoList(
                skuImageRepository.list(new LambdaQueryWrapper<SkuImage>().eq(SkuImage::getSkuId, skuId))
        ));
    }

    /**
     * 同步SKU信息主键集合信息
     * 布隆过滤器重建
     * 1. 定时任务
     * 2. 阈值触发（删除商品时候，在 redis 里面自增，对 某个数取余数，达到条件然后触发）
     * 3. 手动触发
     */
    @Override
    public void syncSkuInfoIdList() {
        // 获取 sku 主键集合
        List<Long> skuIdList = skuInfoRepository.list().stream().map(SkuInfo::getId).toList();

        // 获取布隆过滤器
        RBloomFilter<Long> skuIdNewBloomFilter = redissonClient.getBloomFilter(ProductRedisStringConstant.PRODUCT_SKU_NEW_ID_LIST_KEY);

        // 判断是否初始化
        if (!skuIdNewBloomFilter.isExists()) {
            skuIdNewBloomFilter.tryInit(skuIdList.size(), 0.0000001);
            skuIdNewBloomFilter.add(skuIdList);
        }

        // // 获取布隆过滤器
        // RBloomFilter<Long> skuIdBloomFilter = redissonClient.getBloomFilter(ProductRedisStringConstant.PRODUCT_SKU_ID_LIST_KEY);
        // // 删除对应的值
        // skuIdBloomFilter.delete();
        //
        // // 重命名
        // skuIdNewBloomFilter.rename(ProductRedisStringConstant.PRODUCT_SKU_ID_LIST_KEY);

        // 原子操作
        String script = """
                redis.call('del', KEYS[1]);
                redis.call('del', '{' .. KEYS[1] .. '}:config');
                redis.call('rename', KEYS[2], KEYS[1]);
                redis.call('rename', '{' .. KEYS[2] .. '}:config', '{' .. KEYS[1] .. '}:config');
                """;

        stringRedisTemplate.execute(new DefaultRedisScript<>(script, Long.class),
                List.of(ProductRedisStringConstant.PRODUCT_SKU_ID_LIST_KEY, ProductRedisStringConstant.PRODUCT_SKU_NEW_ID_LIST_KEY));
    }

    /**
     * 商品上架/下架方法
     *
     * @param skuId      商品SKU ID，用于唯一标识一个商品
     * @param onSaleEnum 上架状态枚举，表示商品当前的上架状态
     */
    @Override
    public void onSale(Long skuId, OnSaleEnum onSaleEnum) {
        // 修改数据库中商品的上架状态
        skuInfoRepository.changOnSale(skuId, OnSaleEnum.ON_SALE);
        // 数据库中指定商品保存在 ES 中
    }
}